
package com.cluedo;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;

public class CluedoDataPad {
    /*
     * final static String[] weaponsTokens = { "Candlestick", "Knife", "Pipe", "Gun", "Rope",
     * "Wrench", }; final static String[] characterTokens = { "Scarlet", "Purple", "Green", "White",
     * "Peacock", "Mustard", }; final static String[] roomTokens = { "Kitchen", "Ballroom",
     * "Conservatory", "Dining Room", "Billard Room", "Library", "Lounge", "Hall", "Study" };
     */
    final static String[] weaponsTokens = {
            "Candlestick", "Dagger", "LeadPipe",
            "Revolver", "Rope", "Spanner",
    };
    final static String[] characterTokens = {
            "MissScarlett", "ProfessorPlum", "ReverendGreen",
            "MrsWhite", "MrsPeacock", "ColonelMustard",
    };
    final static String[] roomTokens = {
            "Kitchen", "Ballroom", "Conservatory",
            "DiningRoom", "BilliardRoom", "Library", "Lounge", "Hall", "Study"
    };

    final static ArrayList<String> rooms = new ArrayList<String>();
    final static ArrayList<String> weapons = new ArrayList<String>();
    final static ArrayList<String> characters = new ArrayList<String>();
    final static HashMap<String, Integer> tokens;
    final static String[] entryKeys;
    final static int totalTokens;

    static {
        totalTokens = weaponsTokens.length + characterTokens.length
                + roomTokens.length;
        tokens = new HashMap<String, Integer>(weaponsTokens.length
                + characterTokens.length + roomTokens.length);
        entryKeys = new String[weaponsTokens.length + characterTokens.length
                + roomTokens.length];
        rooms.addAll(Arrays.asList(roomTokens));
        weapons.addAll(Arrays.asList(weaponsTokens));
        characters.addAll(Arrays.asList(characterTokens));

        int counter = 0;
        counter = addTokenData(weaponsTokens, counter);
        counter = addTokenData(roomTokens, counter);
        counter = addTokenData(characterTokens, counter);
    }

    private static int addTokenData(String[] tokenData, int counter) {
        for (String token : tokenData) {
             System.out.println(String.format("%.5s\t%d", token, counter));
            entryKeys[counter] = token;
            tokens.put(token, counter);
            counter++;
        }
        return counter;
    }

    private ArrayList<Player> players;
    private int currPlayer = 0;
    private int turns = 0;
    private int totalPlayers;
    private boolean runManual = false;
    /* Player used for using Main */
    private Player player;

    public static void main(String args[]) {
        @SuppressWarnings("unused")
        CluedoDataPad main = CluedoDataPad.newInstance(true, 0, 3, null);
    }

    /**
     * Grab an instance to interact
     * 
     * @param useTxtFile - this is used for simulation purposes and should be disabled usually
     *            unless for simulations or testing. Its default file it will check for is under
     *            resources/moves.txt 
     * @param playerId - The player that this instance should be for
     * @param players - total amount of players
     * @param cards - cards that this player have
     * @return
     */
    public static CluedoDataPad newInstance(boolean useTxtFile, int playerId, int players,
            ArrayList<String> cards) {
        if (useTxtFile) {
            return new CluedoDataPad(players);
        } else {
            return new CluedoDataPad(playerId, players, cards);
        }
    }

    private CluedoDataPad(int players) {
        start();
    }

    private CluedoDataPad(int playerId, int players, ArrayList<String> cards) {
        initializeGame(playerId, players, cards);
    }

    private void start() {
        System.out.println(String.format("Chara %d, Rooms %d, Weapons %d",
                characters.size(), rooms.size(), weapons.size()));
        try (Scanner scn = new Scanner(new File("resource/moves.txt"))) {
            initializeGame(scn, scn.nextLine());
            if (runManual) {
                while (scn.hasNext()) {
                    String inputLine = scn.nextLine();
                    if (inputLine.trim().equals("exit")) {
                        break;
                    }
                    String[] input = inputLine.split(",");
                    if (input.length > 0 && !input[0].equals("#")) {
                        System.out.println(inputLine);
                        parseProcessInput(input);
                    }
                }
            } else {
                while (turns < 2) {
                    runGameSim();
                }
            }

            System.out.println("Game Ended Turns : " + turns);

            for (Player p : players) {
                p.userGrid.printGrid();
            }
        } catch (FileNotFoundException e) {
            System.err.println("File Not found " + e);
        }
    }

    /**
     * Initializing for actual usage
     * 
     * @param playerId
     * @param totPlayers
     * @param in
     */
    private void initializeGame(int playerId, int totPlayers, ArrayList<String> in) {
        totalPlayers = totPlayers;
        players = new ArrayList<Player>(totalPlayers);

        player = new Player(playerId);

        for (String tk : in) {
            player.addToken(tk);
        }

        player.setDataGrid(DataGrid.newInstance(totalPlayers + 1,
                tokens.size(), entryKeys, this, player));
    }

    /**
     * Initializing for debugging simulation
     * 
     * @param scn
     * @param in
     */
    private void initializeGame(Scanner scn, String in) {
        String[] inputSplit = in.split(",");
        totalPlayers = Integer.valueOf(inputSplit[0]);
        players = new ArrayList<Player>(totalPlayers);

        for (int i = 0; i < totalPlayers; i++) {
            players.add(new Player(i));
        }

        String character = inputSplit[1];
        String weapon = inputSplit[2];
        String room = inputSplit[3];
        if (inputSplit.length == 4) {
            Stack<String> data = new Stack<String>();
            data.addAll(characters);
            data.addAll(rooms);
            data.addAll(weapons);
            data.remove(character);
            data.remove(weapon);
            data.remove(room);
            // Collections.shuffle(data); // In real simulation or create new sample set
            while (!data.isEmpty()) {
                String token = data.pop();
                players.get(currPlayer).addToken(token);
                nextPlayer();
            }
        } else {
            for (int plyr = 0; plyr < totalPlayers; plyr++) {
                String[] cards = scn.nextLine().split("\\t");
                for (String card : cards) {
                    players.get(plyr).addToken(card.trim());
                }
            }
        }

        System.out.println(String.format("Solution\t%.5s\t%.5s\t%.5s\t\n",
                character, weapon, room));

        for (Player player : players) {
            player.setDataGrid(DataGrid.newInstance(totalPlayers + 1,
                    tokens.size(), entryKeys, this, player));
            System.out.println(player.toString());
            System.out.println(player.showTokens());
            player.userGrid.printGrid();
        }
    }

    private void runGameSim() {
        int playerResponse = currPlayer + 1;
        Player p = players.get(currPlayer);
        String[] suggest = p.userGrid.getSuggestion().split(",");
        String playerResponseToken = null;

        suggestionBuilder: for (int initPlyr = currPlayer + 1;; initPlyr++) {
            if (initPlyr > totalPlayers - 1) {
                initPlyr = 0;
            }

            if (initPlyr == currPlayer) {
                break;
            }

            Player plyr = players.get(initPlyr);
            for (String tok : suggest) {
                if (plyr.cards.contains(tok)) {
                    playerResponse = plyr.id;
                    playerResponseToken = tok;
                    break suggestionBuilder;
                }
            }
        }

        if (playerResponseToken != null) {
            String sug = String.format("%d,%s,%s,%s,%d,%s", p.id, suggest[0], suggest[1],
                    suggest[2],
                    playerResponse, playerResponseToken);
            System.out.println(sug);
            parseProcessInput(sug.split(","));
        }
    }

    private void parseProcessInput(String[] input) {
        int PLAYER_RETURN = input.length - 2;
        int PLAYER_RETURN_CARD = input.length - 1;
        if (input.length == 6) {
            String cardResponse = input[PLAYER_RETURN_CARD];
            int playerResponse = Integer.valueOf(input[PLAYER_RETURN]);
            if (tokens.containsKey(cardResponse)) {
                for (Player p : players) {
                    // p.userGrid.getSuggestion();
                    p.userGrid.updateStatisticsGivenResponse(
                            Integer.valueOf(input[0]), playerResponse,
                            Arrays.copyOfRange(input, 1, input.length - 2),
                            cardResponse);
                    p.userGrid.printGrid();
                }
            }
            nextPlayer();
        } else {
            // System.out.println("Input Length Incorrect " + input.length);
        }
    }
    
    public void updatePlayer(int playerReq, int playerResp, String[] request, String tokenResponse) {
        player.userGrid
                .updateStatisticsGivenResponse(playerReq, playerResp, request, tokenResponse);
    }
    
    public void updatePlayerSoftEvidence(int playerReq, int playerResp, String[] request) {
        player.userGrid.updateStatisticsGivenResponse(playerReq, playerResp, request, null);
    }
    
    public String[] getPlayerSuggestion() {
        return player.userGrid.getSuggestion().split(",");
    }

    // ---- Utils
    public static List<String> determineTokenFrom(String gameToken) {
        if (weapons.contains(gameToken)) {
            return weapons;
        } else if (rooms.contains(gameToken)) {
            return rooms;
        } else if (characters.contains(gameToken)) {
            return characters;
        }
        return null;
    }

    private void nextPlayer() {
        currPlayer++;
        if (currPlayer >= totalPlayers) {
            currPlayer = 0;
            turns++;
        }
        System.out.println("Turn " + turns);
    }

    public Player getPlayer() {
        return player;
    }
    
    public float[][] getGrid() {
        return player.userGrid.getGrid();
    }

    public static int getTotaltokens() {
        return totalTokens;
    }
}
